﻿using System;
using System.ComponentModel;
using nRoute.Internal;
using nRoute.Navigation.Containers;
using System.Collections.Generic;
using nRoute.Components.Routing;
using nRoute.Navigation;
using System.Windows;
using nRoute.Components;

namespace nRoute.Controls
{
    public partial class StatefulContainer
		 : IStatefulContainer
    {
        private readonly Dictionary<string, PageContentState> _states;

#region Constructor

        public StatefulContainer()
        {
            _states = new Dictionary<string, PageContentState>(StringComparer.InvariantCultureIgnoreCase);
        }

#endregion

#region IStatefulContainer Members

        public event EventHandler<NavigationContainerEventArgs> JournalPurged;

        public IEnumerable<PageContentState> NavigatedPagesJournal
        {
            get { return _states.Values; }
        }

        public bool HasState(string url)
        {
            if (string.IsNullOrEmpty(url)) return false;
            return _states.ContainsKey(url);
        }

        public void PurgeJournal()
        {
            OnPurgeJournals();
        }

        public bool CanPurgeJournal
        {
            get { return (_states != null && _states.Count > 0); }
        }

#endregion

#region Overrides

        protected override void OnProcessResponse(NavigationResponse response)
        {
            Guard.ArgumentNotNull(response, "response");

            // we won't handle it the response, if it is not the active request!
            if (!response.Request.Equals(base.ActiveNavigationRequest)) return;
            
            // we check if the navigation was not successful we let the base class handle it
            if (response.Status != ResponseStatus.Success)
            {
                base.OnProcessResponse(response);
                return;
            }

            // note_ we don't send this request to the base class, hereon
            // we add to the journal the current page info
            if (base.CurrentNavigationRequest != null)
            {
                if (_states.ContainsKey(base.CurrentNavigationRequest.RequestUrl)) 
                {
                    _states[base.CurrentNavigationRequest.RequestUrl] = GetCurrentPageContentState();
                }
                else
                {
                    _states.Add(base.CurrentNavigationRequest.RequestUrl, GetCurrentPageContentState());
                    base.NotifyPropertyChanged(() => CanPurgeJournal);
                }
            }

            // we save our supporters and use them - note_ we need to save this to access later
            CurrentNavigationLifecycleSupporter = response.NavigationLifecycleSupporter;
            CurrentNavigationStateSupporter = response.NavigationStateSupporter;

            // if the content support navigation, we pass in the request/response merged parameters
            if (this.CurrentNavigationLifecycleSupporter != null)
            {
                CurrentNavigationLifecycleSupporter.Initialize(response.ResponseParameters);
                Title = CurrentNavigationLifecycleSupporter.Title ?? 
                    nRoute.Navigation.Navigation.GetTitle(response.Content as DependencyObject);
            }
            else
            {
                Title = nRoute.Navigation.Navigation.GetTitle(response.Content as DependencyObject);
            }

            // we get the page state manager and restore the state
            if (CurrentNavigationStateSupporter != null)
            {                
                // restore state, if we have a state
                if (_states.ContainsKey(response.Request.RequestUrl))
                    CurrentNavigationStateSupporter.RestoreState(_states[response.Request.RequestUrl].State);  // note_ with stored state
            }

            // we save the url and the content
            CurrentNavigationRequest = response.Request;
            SetValue(ContentProperty, response.Content);

            // and raise the event navigation completed
            OnNavigationCompleted(new NavigatedEventArgs(this, response.Request));
        }

#endregion

#region Journals Related

        protected virtual void OnPurgeJournals()
        {
            if (_states.Count == 0) return;
            _states.Clear();
            
            OnJournalsPurged(new NavigationContainerEventArgs(this));
            base.NotifyPropertyChanged(() => CanPurgeJournal);
        }

#endregion

#region Events Related

        protected virtual void OnJournalsPurged(NavigationContainerEventArgs e)
        {
            if (JournalPurged != null) JournalPurged(this, e);
        }

#endregion

#region Helpers

        private PageContentState GetCurrentPageContentState()
        {            
            // we check the page has a url
            if (base.CurrentNavigationRequest == null) return null;

            // we return the state
            return new PageContentState(this.Url, this.Title, 
                (CurrentNavigationStateSupporter == null ? null : CurrentNavigationStateSupporter.SaveState()));
        }

#endregion

    }
}
